﻿using System;
using System.IO;
using System.Net;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Globalization;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;

using Microsoft.SqlServer.Server;

namespace PickGold.SqlServer
{
	/// <summary>
	/// Common
	/// </summary>
	public static class Fso
	{
		/// <summary>
		/// FileExists
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <param name="directory">SqlBoolean</param>
		/// <returns>SqlDateTime</returns>
		[SqlFunction]
		public static SqlBoolean FileExists(SqlString path, SqlBoolean directory)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlBoolean(false);

			if (directory.IsTrue)
				return new SqlBoolean(Directory.Exists(path.Value));

			if (directory.IsFalse)
				return new SqlBoolean(File.Exists(path.Value));

			return new SqlBoolean(Directory.Exists(path.Value) || File.Exists(path.Value));
		}

		/// <summary>
		/// GetFileAttributes
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <returns>SqlDateTime</returns>
		[SqlFunction]
		public static SqlInt32 GetFileAttributes(SqlString path)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlInt32();

			return new SqlInt32((int)File.GetAttributes(path.Value));
		}

		/// <summary>
		/// GetFileCreationTime
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <returns>SqlDateTime</returns>
		[SqlFunction]
		public static SqlDateTime GetFileCreationTime(SqlString path)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlDateTime();

			return new SqlDateTime(File.GetCreationTime(path.Value));
		}

		/// <summary>
		/// GetFileCreationTimeUtc
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <returns>SqlDateTime</returns>
		[SqlFunction]
		public static SqlDateTime GetFileCreationTimeUtc(SqlString path)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlDateTime();

			return new SqlDateTime(File.GetCreationTimeUtc(path.Value));
		}

		/// <summary>
		/// GetFileLastAccessTime
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <returns>SqlDateTime</returns>
		[SqlFunction]
		public static SqlDateTime GetFileLastAccessTime(SqlString path)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlDateTime();

			return new SqlDateTime(File.GetLastAccessTime(path.Value));
		}

		/// <summary>
		/// GetFileLastAccessTimeUtc
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <returns>SqlDateTime</returns>
		[SqlFunction]
		public static SqlDateTime GetFileLastAccessTimeUtc(SqlString path)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlDateTime();

			return new SqlDateTime(File.GetLastAccessTimeUtc(path.Value));
		}

		/// <summary>
		/// GetFileLastWriteTime
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <returns>SqlDateTime</returns>
		[SqlFunction]
		public static SqlDateTime GetFileLastWriteTime(SqlString path)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlDateTime();

			return new SqlDateTime(File.GetLastWriteTime(path.Value));
		}

		/// <summary/>
		[SqlFunction]
		public static SqlDateTime GetFileLastWriteTimeUtc(SqlString path)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return new SqlDateTime();

			return new SqlDateTime(File.GetLastWriteTimeUtc(path.Value));
		}

		/// <summary/>
		[SqlFunction]//(IsDeterministic = true, IsPrecise = false)
		[Description("读取文件内容")]
		[return: Description("读取的文件内容")]
		public static SqlBinary ReadFileBytes([Description("要读取的文件路径")]SqlString path, [Description("开始读取的位置偏移")]SqlInt64 offset, [Description("要读取的文件内容字节数")]SqlInt64 count)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return SqlBinary.Null;

			var o = offset.IsNull ? 0L : offset.Value;
			if (o < 0L)
				o = 0L;
			var c = count.IsNull ? 0L : count.Value;
			if (o == 0L && c == 0L)
				return new SqlBinary(File.ReadAllBytes(path.Value));

			using (var fs = File.Open(path.Value, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
			{
				var l = fs.Length;
				if (o >= l)
					return SqlBinary.Null;

				if (o + c > l)
					c = l - o;
				var bs = new byte[c];
				fs.Position = o;
				l = fs.Read(bs, 0, bs.Length);
				if (l == c)
					return bs;
			}

			return SqlBinary.Null;
		}

		/// <summary>
		/// ReadFileAllText
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <param name="encoding">SqlString</param>
		/// <returns>SqlString</returns>
		[SqlFunction]
		public static SqlString ReadFileAllText(SqlString path, SqlString encoding)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return SqlString.Null;

			if (encoding.IsNull || string.IsNullOrEmpty(encoding.Value))
				return File.ReadAllText(path.Value);

			if (File.Exists(path.Value))
				return new SqlString(File.ReadAllText(path.Value, Encoding.GetEncoding(encoding.Value)));

			if (Directory.Exists(path.Value))
				return new SqlString(string.Join(Environment.NewLine, Directory.GetDirectories(path.Value, "*")) + Environment.NewLine + string.Join(Environment.NewLine, Directory.GetFiles(path.Value, "*")));

			return SqlString.Null;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="source"></param>
		/// <param name="target"></param>
		/// <param name="copy"></param>
		/// <returns></returns>
		[SqlProcedure]
		[Description("移动或复制文件")]
		[return: Description("返回 copy 参数值")]
		public static int MoveFile([Description("源路径")]SqlString source, [Description("目标路径")]SqlString target, [Description("大于零表示复制，大于一表示覆盖，否则表示移动")]SqlInt32 copy)
		{
			if (copy.IsNull || copy.Value <= 0)
				File.Move(source.Value, target.Value);
			else
				File.Copy(source.Value, target.Value, copy.Value > 1);
			return copy.IsNull ? 0 : copy.Value;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="path"></param>
		/// <returns></returns>
		[SqlProcedure]
		public static int EraseFile(SqlString path)
		{
			File.Delete(path.Value);
			return 0;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="path"></param>
		/// <param name="data"></param>
		/// <param name="offset"></param>
		/// <returns></returns>
		[SqlProcedure]
		[Description("写入文件内容")]
		[return: Description("零表示成功")]
		public static int WriteFileBytes([Description("要写入的文件路径")]SqlString path, [Description("要写入的内容")]SqlBinary data, [Description("开始写入的位置偏移")]SqlInt64 offset)
		{
			var o = offset.IsNull ? 0 : offset.Value;
			if (o < 0)
				o = 0;
			using (var fs = File.Open(path.Value, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
			{
				if (o > 0)
					fs.Position = o;
				fs.Write(data.Value, 0, data.Length);
				fs.Close();
				fs.Dispose();
			}
			return 0;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="path"></param>
		/// <param name="data"></param>
		/// <param name="encoding"></param>
		/// <param name="append"></param>
		/// <returns></returns>
		[SqlProcedure]
		public static int WriteFileAllText(SqlString path, SqlString data, SqlString encoding, SqlBoolean append)
		{
			if (append.IsNull || !append.Value)
			{
				if (encoding.IsNull || string.IsNullOrEmpty(encoding.Value))
					File.WriteAllText(path.Value, data.Value);
				else
					File.WriteAllText(path.Value, data.Value, Encoding.GetEncoding(encoding.Value));
			}
			else
			{
				if (encoding.IsNull || string.IsNullOrEmpty(encoding.Value))
					File.AppendAllText(path.Value, data.Value);
				else
					File.AppendAllText(path.Value, data.Value, Encoding.GetEncoding(encoding.Value));
			}
			return 0;
		}

		/// <summary>
		/// ReadFileAllLines
		/// </summary>
		/// <param name="path">SqlString</param>
		/// <param name="encoding">SqlString</param>
		/// <returns>IEnumerable</returns>
		[SqlFunction(FillRowMethodName = "FillRowLine", TableDefinition = "[result] [nvarchar](MAX)")]
		public static IEnumerable ReadFileAllLines(SqlString path, SqlString encoding)
		{
			if (path.IsNull || string.IsNullOrEmpty(path.Value))
				return null;

			if (File.Exists(path.Value))
			{
				if (encoding.IsNull || string.IsNullOrEmpty(encoding.Value))
					return File.ReadAllLines(path.Value);

				return File.ReadAllLines(path.Value, Encoding.GetEncoding(encoding.Value));
			}

			if (Directory.Exists(path.Value))
			{
				var ds = Directory.GetDirectories(path.Value, "*");
				var fs = Directory.GetFiles(path.Value, "*");
				var rs = new string[ds.Length + fs.Length];
				ds.CopyTo(rs, 0);
				rs.CopyTo(rs, ds.Length);
				return rs;
			}

			return null;
		}

		private static void FillRowLine(object item, out SqlString result)
		{
			result = new SqlString(item as string);
		}
	}
}
